﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Collections.Generic;

namespace ZD.PointsMall.Core
{
    /// <summary>
    /// 加解密包装器
    /// </summary>
    public sealed class SecurityWrapper
    {
        private static char[] m_Constant_Chars =
        {
            '0','1','2','3','4','5','6','7','8','9',
            'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
            'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
        };

        private static SecurityWrapper m_Instance;
        public static SecurityWrapper Instance
        {
            get
            {
                if (m_Instance == null)
                {
                    m_Instance = new SecurityWrapper();
                }
                return m_Instance;
            }
        }

        private static Encoding m_DefEncoding = Encoding.UTF8;

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public string Encrypt(string input, string key)
        {
            if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(key))
            {
                return string.Empty;
            }
            return this.AESEncrypt(input, key);
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public string Decrypt(string input, string key)
        {
            if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(key))
            {
                return string.Empty;
            }
            return this.AESDecrypt(input, key);
        }

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private string AESEncrypt(string input, string key)
        {
            var encryptKey = m_DefEncoding.GetBytes(key);

            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(encryptKey, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (var swEncrypt = new StreamWriter(csEncrypt))
                            {
                                swEncrypt.Write(input);
                            }
                        }

                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        return Convert.ToBase64String(result);
                    }
                }
            }
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private string AESDecrypt(string input, string key)
        {
            var fullCipher = Convert.FromBase64String(input);

            var iv = new byte[16];
            var cipher = new byte[fullCipher.Length - iv.Length];

            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, cipher.Length);
            var decryptKey = m_DefEncoding.GetBytes(key);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(decryptKey, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
        }

        /// <summary>
        /// 自定义Base64加密
        /// </summary>
        /// <param name="input">明文</param>
        /// <returns>密文</returns>
        public string CBase64Encrypt(string input)
        {
            try
            {
                if (string.IsNullOrEmpty(input))
                {
                    return input;
                }

                Random rnd = new Random();
                var bytes = m_DefEncoding.GetBytes(input);

                var text = Convert.ToBase64String(bytes);
                var s1 = string.Join("", Enumerable.Range(1, 10).Select(_ => m_Constant_Chars[rnd.Next(62)]).ToArray());
                var s2 = string.Join("", Enumerable.Range(1, 6).Select(_ => m_Constant_Chars[rnd.Next(62)]).ToArray());
                var s3 = string.Join("", Enumerable.Range(1, 8).Select(_ => m_Constant_Chars[rnd.Next(62)]).ToArray());
                int len = text.Length;
                int mPoint = len / 2;

                var str = string.Concat(s1, text.Substring(0, mPoint), s2, text.Substring(mPoint), s3);

                return str;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 自定义Base64解密
        /// </summary>
        /// <param name="input">密文</param>
        /// <returns>明文</returns>
        public string CBase64Decrypt(string input)
        {
            try
            {
                if (string.IsNullOrEmpty(input))
                {
                    return input;
                }

                string s = input.Substring(10);
                s = s.Substring(0, s.Length - 8);
                int len = s.Length;
                int mPoint = len / 2;
                string str = string.Concat(s.Substring(0, mPoint - 3), s.Substring(mPoint + 3));

                var bytes = Convert.FromBase64String(str);

                string text = m_DefEncoding.GetString(bytes);
                return text;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 哈希密文
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public string HashEncrypt(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }

            try
            {
                // change according to your needs, an UTF8Encoding
                // could be more suitable in certain situations
                //ASCIIEncoding encoding = new ASCIIEncoding();

                byte[] textBytes = m_DefEncoding.GetBytes(input);
                byte[] keyBytes = textBytes.Reverse().ToArray();

                byte[] hashBytes;

                using (HMACSHA256 hash = new HMACSHA256(keyBytes))
                { hashBytes = hash.ComputeHash(textBytes); }

                return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 自定义加密（用于卡号）
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private byte[] CusEnrypt(string str, Encoding encoding)
        {
            // base64编码
            var s = Convert.ToBase64String(encoding.GetBytes(str.Trim()));
            var enData = encoding.GetBytes(s);

            // 移位
            int len = enData.Length;
            for (int i = 0; i < len; i++)
            {
                byte b = enData[i];
                if (i % 2 == 0)
                {
                    enData[i] = (byte)((int)b + i);
                }
            }

            // 反序
            byte[] data2 = enData.Reverse().ToArray();
            return data2;
        }

        /// <summary>
        /// 自定义解密（用于卡号）
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private byte[] CusDecrypt(byte[] data, Encoding encoding)
        {
            var len = data.Length;

            //反序
            var data1 = data.Reverse().ToArray();

            // 移位
            for (int i = 0; i < len; i++)
            {
                byte b = data1[i];
                if (i % 2 == 0)
                {
                    data1[i] = (byte)((int)b - i);
                }
            }

            // base64编码
            var data2 = Convert.FromBase64String(encoding.GetString(data1));

            return data2;
        }

        /// <summary>
        /// 是否相等
        /// </summary>
        /// <param name="enStr">密文</param>
        /// <param name="str">明文</param>
        /// <param name="salt">盐值</param>
        /// <returns></returns>
        public bool IsEquals(string enStr, string str, string salt)
        {
            var p = this.Decrypt(enStr, salt);
            return p.Equals(str);
        }

        /// <summary>
        /// 验证密码
        /// </summary>
        /// <param name="enPwd">密文密码</param>
        /// <param name="pwd">明文密码</param>
        /// <param name="salt">盐值</param>
        /// <returns></returns>
        public bool VerifyPassword(string enPwd, string pwd, string salt)
        {
            return IsEquals(enPwd, pwd, salt);
        }


        /// <summary>
        /// 去掉右边的 0 byte
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public byte[] TrimRight(byte[] data)
        {
            List<byte> lst = new List<byte>();
            int len = data.Length;
            for (int i = (len - 1); i >= 0; i--)
            {
                if (data[i] == ((byte)0))
                {
                    continue;
                }

                lst.AddRange(data.Take(i + 1));
                break;
            }
            return lst.ToArray();
        }

        /// <summary>
        /// md5密文
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public string Md5Encrypt(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }

            try
            {
                //初始化MD5对象
                MD5 md5 = MD5.Create();

                //将源字符串转化为byte数组
                Byte[] soucebyte = m_DefEncoding.GetBytes(input);

                //soucebyte转化为mf5的byte数组
                Byte[] md5bytes = md5.ComputeHash(soucebyte);

                //将md5的byte数组再转化为MD5数组
                StringBuilder sb = new StringBuilder();
                foreach (Byte b in md5bytes)
                {
                    //x表示16进制，2表示2位
                    sb.Append(b.ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
